/**
 * Created by diozhu on 2017/2/11.
 */
import Vue from 'vue';

const ctx = '@@Swipe';

// === base ===

let throttle = function (fn, delay) { //eslint-disable-line
        let now, lastExec, timer, context, args; //eslint-disable-line

        let execute = function () {
            fn.apply(context, args);
            lastExec = now;
        };

        return function () {
            context = this;
            args = arguments;

            now = Date.now();

            if (timer) {
                clearTimeout(timer);
                timer = null;
            }

            if (lastExec) {
                let diff = delay - (now - lastExec);
                if (diff < 0) {
                    execute();
                } else {
                    timer = setTimeout(() => {
                        execute();
                    }, diff);
                }
            } else {
                execute();
            }
        };
    },

    isAttached = function (element) {
        var currentNode = element.parentNode;
        while (currentNode) {
            if (currentNode.tagName === 'HTML') {
                return true;
            }
            if (currentNode.nodeType === 11) { // DocumentFragment node
                return false;
            }
            currentNode = currentNode.parentNode;
        }
        return false;
    },

    doBind = function () { // bind once
        if (this.binded) return; // eslint-disable-line
        this.binded = true;
        let directive = this,
            element = directive.el;
        directive.distance = element.getAttribute('swipe-distance'); // 修正距离

        directive.swipeEventTarget = element;
        directive.startListener = swipeStart.bind(directive);
        directive.movingListener = swiping.bind(directive);
        directive.endListener = swipeEnd.bind(directive);
        // directive.startListener = throttle(swipeStart.bind(directive), 10);
        // directive.movingListener = throttle(swiping.bind(directive), 10);
        // directive.endListener = throttle(swipeEnd.bind(directive), 10);
        directive.swipeEventTarget.addEventListener('touchstart', directive.startListener, false);
        directive.swipeEventTarget.addEventListener('touchmove', directive.movingListener, false);
        directive.swipeEventTarget.addEventListener('touchend', directive.endListener, false);
    },

    swipeStart = function (e) {
        this.direction = '';
        this.startX = e.touches[0].clientX;
        this.startY = e.touches[0].clientY;
    },

    swiping = function (e) {
        // if (this.startY < this.el.getBoundingClientRect().top && this.startY > this.el.getBoundingClientRect().bottom) return true; // 超出范围
        this.currentX = e.touches[0].clientX;
        this.currentY = e.touches[0].clientY;
        let x = this.currentX - this.startX,
            y = this.currentY - this.startY;
        if (Math.abs(x) > Math.abs(y) && x >= this.distance) { // right
            this.direction = 'right';
        } else if (Math.abs(x) > Math.abs(y) && x <= -this.distance) { // left
            this.direction = 'left';
        } else if (Math.abs(x) < Math.abs(y) && y >= this.distance) { // up
            this.direction = 'down';
        } else if (Math.abs(x) < Math.abs(y) && y <= -this.distance) { // down
            this.direction = 'up';
        }
    },

    swipeEnd = function (e) {
        let direction = this.el.getAttribute('swipe-direction');

        if (this.direction === direction && typeof this.expression === 'function') {
            this.expression();
        }
    };

// === infinite scrolll ===

let Swipe = {
    bind (el, binding, vnode) {
        el[ctx] = {
            el,
            vm: vnode.context,
            // vm: vnode.componentInstance,
            expression: binding.value
        };
        const args = arguments;
        el[ctx].vm.$on('hook:mounted', function () {
            el[ctx].vm.$nextTick(function () {
                if (isAttached(el)) {
                    doBind.call(el[ctx], args);
                    return; // Add by Dio Zhu. on 2017.2.14
                }

                el[ctx].bindTryCount = 0;

                let tryBind = function () {
                    if (el[ctx].bindTryCount > 10) return; //eslint-disable-line
                    el[ctx].bindTryCount++;
                    if (isAttached(el)) {
                        doBind.call(el[ctx], args);
                    } else {
                        setTimeout(tryBind, 50);
                    }
                };

                tryBind();
            });
        });
    },

    unbind (el) {
        el[ctx].swipeEventTarget.removeEventListener('touchstart', el[ctx].startListener);
        el[ctx].swipeEventTarget.removeEventListener('touchmove', el[ctx].movingListener);
        el[ctx].swipeEventTarget.removeEventListener('touchend', el[ctx].endListener);
    }
};

// === install ===

const install = function (Vue) {
    Vue.directive('Swipe', Swipe);
};

if (!Vue.prototype.$isServer && window.Vue) {
    window.Fixed = Swipe;
    Vue.use(install); // eslint-disable-line
}

Swipe.install = install;
export default Swipe;
